home *** CD-ROM | disk | FTP | other *** search
/ The 640 MEG Shareware Studio 2 / The 640 Meg Shareware Studio CD-ROM Volume II (Data Express)(1993).ISO / clang / nn.zip / DIGEST.C < prev    next >
C/C++ Source or Header  |  1989-12-31  |  10KB  |  425 lines

  1. /*
  2.  * digest article handling
  3.  */
  4.  
  5. #include "config.h"
  6. #include "news.h"
  7. #include "match.h"
  8. #include "debug.h"
  9.  
  10. #ifdef DG_TEST
  11.  
  12. #define TEST(fmt, x, y) if (Debug & DG_TEST) printf(fmt, x, y)
  13.  
  14. #else
  15.  
  16. #define TEST(fmt, x, y)
  17.  
  18. #endif
  19.  
  20.  
  21.  
  22. /*
  23.  * test if global 'news' header is header of a digest.
  24.  * body points to a buffer (NUL term)
  25.  * containing the first part of the article.
  26.  */
  27.  
  28. static char match_digest[128] = {
  29.     
  30. /*  NUL SOH STX ETX EOT ENQ ACK BEL BS  TAB NL  VT  FF  CR  SO  SI  */
  31.     00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 
  32.  
  33. /*  DLE DC1 DC2 DC3 DC4 NAK SYN ETB CAN EM  SUB ESC FS  GS  RS  US  */
  34.     00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 
  35.  
  36. /*  SP  !   "   #   $   %   &   '   (   )   *   +   ,   -   .   /   */
  37.     00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 
  38.  
  39. /*  0   1   2   3   4   5   6   7   8   9   :   ;   <   =   >   ?   */
  40.      1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 00, 00, 00, 00, 00, 00, 
  41.  
  42. /*  @   A   B   C   D   E   F   G   H   I   J   K   L   M   N   O   */
  43.     00, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,
  44.  
  45. /*  P   Q   R   S   T   U   V   W   X   Y   Z   [   \   ]   ^   _   */
  46.     26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 00, 00, 
  47.  
  48. /*  `   a   b   c   d   e   f   g   h   i   j   k   l   m   n   o   */
  49.     00, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,
  50.  
  51. /*  p   q   r   s   t   u   v   w   x   y   z   {   |   }   ~   DEL */
  52.     26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 00, 00
  53.  
  54. };
  55.  
  56. static char digest_pattern[] = "digest";
  57.  
  58. init_digest_parsing()
  59. {
  60.     init_quick_match(digest_pattern);
  61. }
  62.  
  63.  
  64. is_digest(body)
  65. register char *body;
  66. {
  67.     char *dpos, *quick_match();
  68.     register char *sp;
  69.     register int l;
  70.  
  71.     /* articles without a subject line are not digests (per definition) */
  72.     if (news.ng_subj == NULL) return 0;
  73.     
  74.  
  75.     if (dpos = quick_match(news.ng_subj, digest_pattern)) {
  76.     int lgt = dpos - news.ng_subj;
  77.     int maxl = 10;
  78.     
  79.     /* look for a line matching the subject */
  80.     while (*body && maxl) {
  81.         sp = news.ng_subj;
  82.         l = lgt;
  83.         if (*body == *sp && strncmp(body, sp, l) == 0) 
  84.         goto ok;
  85.         while (*body && *body != NL) {
  86.         while (*sp && MATCH_DROP(match_digest, *sp)) {
  87.             if (--l == 0) goto ok;
  88.             ++sp;
  89.         }
  90.         
  91.         if (MATCH_DROP(match_digest, *body)) {
  92.             ++body;
  93.             continue;
  94.         }
  95.         
  96.         if (*sp && MATCH_EQ(match_digest, *body, *sp)) {
  97.             if (--l == 0) goto ok;
  98.             ++sp;
  99.         }
  100.         ++body;
  101.         }
  102.         
  103.         if (*body) ++body, --maxl;
  104.     }
  105.     }
  106.     return 0;
  107.  
  108.  ok:
  109.     TEST("is_digest: %s\n", news.ng_subj, 0);
  110.     return 1;
  111. }
  112.  
  113.  
  114. /*
  115.  * expect that f is positioned at header of an article
  116.  */
  117.  
  118. static int is_mmdf_folder = 0;
  119.  
  120. get_digest_article(f, hdrbuf)
  121. FILE *f;
  122. news_header_buffer hdrbuf;
  123. {
  124.     int cont;
  125.     
  126.     digest.dg_hpos = ftell(f);
  127.     TEST("GET DIGEST hp=%ld\n", digest.dg_hpos, 0);
  128.     
  129.     do {
  130.     if (!parse_digest_header(f, 0, hdrbuf)) return -1;
  131.     digest.dg_fpos = ftell(f);
  132.     TEST("END HEADER hp=%ld fp=%ld\n", digest.dg_hpos, digest.dg_fpos);
  133.     } while ((cont = skip_digest_body(f)) < 0);
  134.  
  135.     TEST("END BODY lp=%ld next=%ld\n", digest.dg_lpos, ftell(f));
  136.  
  137.     return cont;
  138. }    
  139.     
  140. #define BACKUP_LINES     50    /* remember class + offset for parsed lines */
  141.  
  142. #define    LN_BLANK    0x01    /* blank line */
  143. #define    LN_DASHED    0x02    /* dash line */
  144. #define    LN_HEADER    0x04    /* (possible) header line */
  145. #define    LN_ASTERISK    0x08    /* asterisk line (near end) */
  146. #define    LN_END_OF    0x10    /* End of ... line */
  147. #define    LN_TEXT        0x20    /* unclassified line */
  148.  
  149.  
  150. /*
  151.  * skip until 'Subject: ' (or End of digest) line is found
  152.  * then backup till start of header
  153.  */
  154.  
  155. /*
  156.  * Tuning parameters:
  157.  *
  158.  *    MIN_HEADER_LINES:    number of known header lines that must
  159.  *                be found in a block to identify a new
  160.  *                header
  161.  *
  162.  *    MAX_BLANKS_DASH        max no of blanks on a 'dash line'
  163.  *
  164.  *    MIN_DASHES        min no of dashes on a 'dash line'
  165.  *
  166.  *    MAX_BLANKS_ASTERISKS    max no of blanks on an 'asterisk line'
  167.  *
  168.  *    MIN_ASTERISKS        min no of asterisks on an 'asterisk line'
  169.  *
  170.  *    MAX_BLANKS_END_OF    max no of blanks before "End of "
  171.  */
  172.  
  173. #define    MIN_HEADER_LINES    2
  174. #define    MAX_BLANKS_DASH        3
  175. #define    MIN_DASHES        16
  176. #define    MAX_BLANKS_ASTERISK    1
  177. #define    MIN_ASTERISKS        10
  178. #define    MAX_BLANKS_END_OF    1
  179.  
  180. skip_digest_body(f)
  181. register FILE *f;
  182. {
  183.     off_t  backup_p[BACKUP_LINES];
  184.     int       line_type[BACKUP_LINES];
  185.     register int backup_index, backup_count;
  186.     int    more_header_lines, end_or_asterisks, blanks;
  187.     char   line[1024];
  188.     register char *cp;
  189.     char **dg_hdr_field();
  190.  
  191. #define    decrease_index()    \
  192.     if (--backup_index < 0) backup_index = BACKUP_LINES - 1
  193.  
  194.     backup_index = -1;
  195.     backup_count = 0;
  196.     end_or_asterisks = 0;
  197.     
  198.     digest.dg_lines = 0;
  199.     
  200.     
  201.  next_line:
  202.     more_header_lines = 0;
  203.  
  204.  next_possible_header_line:
  205.     digest.dg_lines++;
  206.  
  207.     if (++backup_index == BACKUP_LINES) backup_index = 0;
  208.     if (backup_count < BACKUP_LINES) backup_count++;
  209.     
  210.     backup_p[backup_index] = ftell(f);
  211.     line_type[backup_index] = LN_TEXT;
  212.  
  213.     if (fgets(line, 1024, f) == NULL) {
  214.     TEST("end_of_file, bc=%d, lines=%d\n", backup_count, digest.dg_lines);
  215.     
  216.     if (is_mmdf_folder) {
  217.         digest.dg_lpos = backup_p[backup_index];
  218.         is_mmdf_folder = 0;
  219.         return 0;
  220.     }
  221.     
  222.     /* end of file => look for "****" or "End of" line */
  223.  
  224.     if (end_or_asterisks)
  225.         while (--backup_count >= 0) {
  226.         --digest.dg_lines;
  227.         decrease_index();
  228.         if (line_type[backup_index] & (LN_ASTERISK | LN_END_OF)) break;
  229.         }
  230.     
  231.     if (digest.dg_lines == 0) return 0;
  232.     
  233.     while (--backup_count >= 0) {
  234.         --digest.dg_lines;
  235.         digest.dg_lpos = backup_p[backup_index];
  236.         decrease_index();
  237.         if ((line_type[backup_index] & 
  238.         (LN_ASTERISK | LN_END_OF | LN_BLANK | LN_DASHED)) == 0)
  239.         break;
  240.     }
  241.  
  242.     return 0;    /* no article follows */
  243.     }
  244.  
  245.     TEST("\n>>%-.50s ==>>", line, 0);
  246.  
  247.     if (line[0] == '\001' && strcmp(line, "\001\001\001\001\n") == 0) {
  248.     digest.dg_lpos = backup_p[backup_index];
  249.     if (!is_mmdf_folder) fseek(f, digest.dg_lpos, 0);
  250.     --digest.dg_lines;
  251.     is_mmdf_folder = 0;
  252.     return (digest.dg_lines <= 0) ? -1 : 1;
  253.     }
  254.         
  255.     if (is_mmdf_folder) goto next_line;
  256.     
  257.     for (cp = line; *cp && isascii(*cp) && isspace(*cp); cp++);
  258.  
  259.     if (*cp == NUL) {
  260.     TEST("BLANK", 0, 0);
  261.     line_type[backup_index] = LN_BLANK;
  262.     goto next_line;
  263.     }
  264.     
  265.     blanks = cp - line;
  266.     
  267.     if (*cp == '-') {
  268.     if (blanks > MAX_BLANKS_DASH) goto next_line;
  269.     
  270.     while (*cp == '-') cp++;
  271.     if (cp - line - blanks > MIN_DASHES) {
  272.         while (*cp && (*cp == '-' || (isascii(*cp) && isspace(*cp)))) cp++;
  273.         if (*cp == NUL) {
  274.         TEST("DASHED", 0, 0);
  275.         
  276.         line_type[backup_index] = LN_DASHED;
  277.         }
  278.         
  279.     }
  280.     goto next_line;
  281.     }
  282.         
  283.     if (*cp == '*') {
  284.     if (blanks > MAX_BLANKS_ASTERISK) goto next_line;
  285.     
  286.     while (*cp == '*') cp++;
  287.     if (cp - line - blanks > MIN_ASTERISKS) {
  288.         while (*cp && (*cp == '*' || (isascii(*cp) && isspace(*cp)))) cp++;
  289.         if (*cp == NUL) {
  290.         TEST("ASTERISK", 0, 0);
  291.         line_type[backup_index] = LN_ASTERISK;
  292.         end_or_asterisks++;
  293.         }
  294.     }
  295.     goto next_line;
  296.     }
  297.  
  298.     if (blanks <= MAX_BLANKS_END_OF && 
  299.     *cp == 'E' && strncmp(cp, "End of ", 7) == 0) {
  300.     TEST("END_OF_", 0, 0);
  301.     line_type[backup_index] = LN_END_OF;
  302.     end_or_asterisks++;
  303.     goto next_line;
  304.     }
  305.     
  306.     if (blanks == 0) {
  307.     if (dg_hdr_field(line, 0)) {
  308.         TEST("HEADER", 0, 0);
  309.         
  310.         line_type[backup_index] = LN_HEADER;
  311.         if (++more_header_lines < MIN_HEADER_LINES) 
  312.         goto next_possible_header_line;
  313.  
  314.         /* found block with MIN_HEADER_LINES */
  315.  
  316.         /* search for beginning of header */
  317.  
  318.         TEST("\nSearch for start of header\n", 0, 0);
  319.  
  320.         for (;;) {
  321.         fseek(f, backup_p[backup_index], 0);
  322.         --digest.dg_lines;
  323.         if (--backup_count == 0) break;
  324.         decrease_index();
  325.         if ((line_type[backup_index] & (LN_HEADER | LN_TEXT)) == 0)
  326.             break;
  327.         }
  328.  
  329.         if (digest.dg_lines == 0) {
  330.         TEST("Skipped empty article\n", 0, 0);
  331.         return -1;
  332.         }
  333.         
  334.         for (;;) {
  335.         digest.dg_lpos = backup_p[backup_index];
  336.         if (--backup_count < 0) break;
  337.         decrease_index();
  338.         if ((line_type[backup_index] & (LN_BLANK | LN_DASHED)) == 0)
  339.             break;
  340.         --digest.dg_lines;
  341.         }
  342.  
  343.         return (digest.dg_lines == 0) ? -1 : 1;
  344.     }
  345.     goto next_possible_header_line;
  346.     }
  347.     
  348.     goto next_line;
  349. }    
  350.  
  351.  
  352. parse_digest_header(f, all, hdrbuf)
  353. FILE *f;
  354. int all;
  355. news_header_buffer hdrbuf;
  356. {
  357.     extern char *parse_header(), **dg_hdr_field();
  358.     
  359.     digest.dg_date = digest.dg_from = digest.dg_subj = digest.dg_to = NULL;
  360.      
  361.     parse_header(f, dg_hdr_field, all, hdrbuf);
  362.     
  363.     return digest.dg_from || digest.dg_subj;
  364. }
  365.  
  366.  
  367. static char **dg_hdr_field(lp, all)
  368. register char *lp;
  369. int all;
  370. {
  371.     
  372. #define check(name, lgt, field) \
  373.     if (strncmp(name, lp, lgt) == 0) { \
  374.     TEST("MATCH: field ", 0, 0); \
  375.     return &digest.field; \
  376.     }
  377.     
  378.  
  379.     TEST("\nPARSE[%.20s] ==>> ", lp, 0);
  380.     
  381.     switch (*lp++) {
  382.  
  383.      case '\001':
  384.     if (!is_mmdf_folder && strncmp(lp, "\001\001\001\n", 4) == 0) {
  385.         is_mmdf_folder = 1;
  386.         digest.dg_hpos += 5;
  387.         return NULL;
  388.     }
  389.     break;
  390.     
  391.      case 'D':
  392.      case 'd':    
  393.     check("ate: ",    5, dg_date);
  394.     break;
  395.  
  396.      case 'F':
  397.      case 'f':
  398.     check("rom: ",    5, dg_from);
  399.     break;
  400.  
  401.      case 'R':
  402.      case 'r':
  403.     if (!all) break;
  404.     check("e: ",    3, dg_subj);
  405.     break;
  406.  
  407.      case 'S':
  408.      case 's':
  409.     check("ubject",    6, dg_subj);
  410.     break;
  411.  
  412.      case 'T':
  413.      case 't':
  414.     check("itle: ",    6, dg_subj);
  415.     if (!all) break;
  416.     check("o: ",    3, dg_to);
  417.     break;
  418.     }
  419.     
  420. #undef check
  421.     TEST("NOT MATCHED ", 0, 0);
  422.     
  423.     return NULL;
  424. }
  425.